Code to run analysis and generate figures for McNeall et al. (2023?) “Constraining the carbon cycle in JULES-ES-1.0”


source("JULES-ES-1p0-common-packages.R")
source("JULES-ES-1p0-common-functions.R")
source("JULES-ES-1p0-common-data.R")

0.1 Failure analysis



low_npp_ix <- which(Y[,'npp_nlim_lnd_sum'] < 1e5)
# code from https://stackoverflow.com/questions/28182872/how-to-use-different-sets-of-data-in-lower-and-upper-panel-of-pairs-function-in


#X <- matrix(runif(300), ncol=3)
#Y <- matrix(c(sort(runif(100, 0, 10)), 
#              sort(runif(100, 0, 10)), 
#              sort(runif(100, 0, 10))), ncol=3)

#pdf(file = 'figs/run-failure-pairs.pdf', width = 12, height = 10)
x1 <- X[low_npp_ix, ]
x2 <- X_nlevel0

XY <- rbind(x1, x2)


pairs(XY,
      lower.panel=function(x, y, ...) {
        Xx <- x[seq_len(nrow(x1))] # corresponds to X subset
        Xy <- y[seq_len(nrow(x1))] # corresponds to X subset
        #usr <- par("usr"); on.exit(par(usr))
        #par(usr = c(range(x1[, -ncol(x1)]), range(x1[, -1]))) # set up limits
        points(Xx, Xy, col = zblue, pch = 19, cex = 0.8)
       # if(par('mfg')[2] == 1) axis(2) # if left plot, add left axis
        #if(par('mfg')[1] == ncol(x1)) axis(1) # if bottom plot add bottom axis
      }, 
      upper.panel=function(x, y, ...) {
        Yx <- x[(nrow(x1) + 1):length(x)] # Y subset
        Yy <- y[(nrow(x1) + 1):length(y)] # Y subset
        
        #cntr <- outer(Yx, Yx, FUN='*') # arbitrary function for contour
       # usr <- par("usr"); on.exit(par(usr))
        #par(usr = c(range(x2[, -1]), range(x2[, -ncol(x2)]))) # set up limits
        points(Yx, Yy, col = zred, pch = 19, cex = 0.8)
        #contour(Yx, Yy, cntr, add=TRUE)
        #if(par('mfg')[2] == ncol(x2)) axis(4) # if right plot, add right axis
        #if(par('mfg')[1] == 1) axis(3) # if top plot, add top axis
      }, 
      #tick=FALSE, # suppress the default tick marks
      #line=1,
      gap = 0,
      xlim = c(0,1), ylim = c(0,1),
      labels = 1:d,
      oma = c(2, 18, 2, 2)) # move the default tick labels off the plot 

reset()

legend('left', legend = paste(1:d, colnames(lhs)), cex = 1.1, bty = 'n')
legend('topleft', pch = 19, col = c( zred, zblue), legend = c('failed', 'zero carbon cycle'), bty = 'n', inset = 0.02, cex = 1.1 )


#dev.off()

1 Visualising the ensemble range

It’s important to remember that the design of the experiment is multiplication factors of the original parameters. This might be important for the “hold” value in a sensitivity analysis, as the “standard” value and the median value of the ensemble will not be the same.


#pdf(file = 'figs/lhs_range.pdf', width = 6, height = 8)
par(las = 1, mar = c(5,8,2,1))
lhs_min <- apply(lhs_wave0_wave01_all, 2, min)
lhs_max <- apply(lhs_wave0_wave01_all,2, max)

plot(lhs_max, 1:d, type = 'n', xlim = c(0,10), axes = FALSE, xlab = 'multiplying factor', ylab = '')

abline(v = 0, lty = 'dashed', col = 'grey')
abline(v = 1, lty = 'dashed', col = 'tomato2')

segments(x0 = lhs_min, y0 = 1:d, x1 = lhs_max, y1 = 1:d )
points(lhs_min, 1:d, pch = 20)
points(lhs_max, 1:d, pch = 20)
axis(2, at = 1:d, labels = colnames(lhs))
axis(1)

#dev.off()

1.1 Wave00/Wave01 Ensemble behaviour in key (constraining) outputs.

Global mean for the 20 years at the end of the 20th Century. There is still a significant low bias on cVeg output.

wave00col <- 'skyblue2'
wave01col <- 'tomato2'

wave00col <- 'dodgerblue2'
wave01col <- 'firebrick'
rangecol <- 'grey'
# Histogram of level 1 constraints
hcol = 'darkgrey'
lcol = 'black'

#pdf(file = 'figs/level_2_constraints_hists.pdf', width = 8, height = 8)
par(mfrow = c(2,2), fg = 'darkgrey', las = 1, oma = c(0.1, 0.1, 4, 0.1))

trunc <- function(x, vec){
  
  dat <- x[x < max(vec) & x > min(vec)  ]
  
  dat
  
}


h <- hist(Y_const_level1a_scaled[,'nbp_lnd_sum'], main = 'NBP', xlab = 'GtC/year', col = makeTransparent(wave00col,150))
hist(trunc(Y_const_wave01_scaled [,'nbp_lnd_sum'], h$breaks) ,
     col = makeTransparent(wave01col,150) , breaks = h$breaks, add = TRUE)

rug(Y_const_stan_scaled['nbp_lnd_sum'], lwd = 2)

polygon(x = c(0, 100, 100, 0), y = c(0, 0, 1000, 1000),
        col = makeTransparent(rangecol, 60),
        border = makeTransparent(rangecol))

h <- hist(Y_const_level1a_scaled[,'npp_nlim_lnd_sum'],col = makeTransparent(wave00col,150), main = 'NPP', xlab = 'GtC/year')
hist(trunc(Y_const_wave01_scaled [,'npp_nlim_lnd_sum'], h$breaks) , 
     col = makeTransparent(wave01col) , breaks = h$breaks, add = TRUE)

rug(Y_const_stan_scaled['npp_nlim_lnd_sum'], lwd = 2)

polygon(x = c(35, 80, 80, 35), y = c(0, 0, 1000, 1000),
        col = makeTransparent(rangecol, 60),
        border = makeTransparent(rangecol))


h <- hist(Y_const_level1a_scaled[,'cSoil_lnd_sum'], col = makeTransparent(wave00col,150), main = 'Soil Carbon', xlab = 'GtC')
hist(trunc(Y_const_wave01_scaled [,'cSoil_lnd_sum'], h$breaks) , 
     col = makeTransparent(wave01col,150) , breaks = h$breaks, add = TRUE)

rug(Y_const_stan_scaled['cSoil_lnd_sum'], lwd = 2)

polygon(x = c(750, 3000, 3000, 750), y = c(0, 0, 1000, 1000),
        col = makeTransparent(rangecol, 60),
        border = makeTransparent(rangecol))

h <- hist(Y_const_level1a_scaled[,'cVeg_lnd_sum'], col = makeTransparent(wave00col,150), main = 'Vegetation Carbon', xlab = 'GtC')
hist(trunc(Y_const_wave01_scaled [,'cVeg_lnd_sum'], h$breaks) , 
   col = makeTransparent(wave01col,150)  , breaks = h$breaks, add = TRUE)

rug(Y_const_stan_scaled['cVeg_lnd_sum'], lwd = 2)

polygon(x = c(300, 800, 800, 300), y = c(0, 0, 1000, 1000),
        col = makeTransparent(rangecol, 60),
       border =  makeTransparent(rangecol))



reset()

legend('top', horiz = TRUE, fill = c(makeTransparent(wave00col, 150), makeTransparent(wave01col, 150), makeTransparent(rangecol, 60)), legend = c('Wave00', 'Wave01', 'AW range'))


#dev.off()

1.2 What proportion of wave01 fall within Andy Wiltshire’s constraints?

Just under a third. Points at a significant model discrepency in cVeg

Of the 400 members of the wave01 ensemble, 128 pass Andy Wiltshire’s Level 2 constraints.


length(level2_ix_wave01)
[1] 128
length(level2_ix_wave01) / ntrain_wave01
[1] 0.32

lcol_wave0 <- makeTransparent('dodgerblue2',  120)
lcol_wave01 <- makeTransparent('firebrick',  120)
lcol_wave01_level2 <- 'gold'
stancol = 'black'

linePlotMultiEns <- function(years, ens1, ens2, ens3, col1, col2, col3, ylab, main, ylim = NULL){
  # Plot wave00 and wave01 timeseries on top of one another
  
  nt <- length(years) 
  if(is.null(ylim)){
    
  ylim = range(c(ens1[,1], ens1[,nt], ens2[,1], ens2[ ,nt], ens3[,1], ens3[, nt]))
  }
  
  else ylim <- ylim
  
  matplot(years, t(ens1), type = 'l', lty = 'solid',ylim = ylim, col = col1,
        ylab = ylab, main = main, xlab = '',
        bty = 'n')
  matlines(years, t(ens2), col = col2, lty = 'solid')
    matlines(years, t(ens3), col = col3, lty = 'solid')
}

#pdf(file = 'figs/carbon-cycle-timeseries-waves-constrained.pdf', width = 10, height = 12)
par(mfrow= c(3,5), las = 1, mar = c(4,4,1,0))

linePlotMultiEns(years = years, ens1 = npp_ens_wave00[without_outliers_ix_wave00,],
                 ens2 = npp_ens_wave01[without_outliers_ix_wave01,],
                 ens3 = npp_ens_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'NPP')

lines(years,npp_stan, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 =  nbp_ens_wave00[without_outliers_ix_wave00,], 
                 ens2 = nbp_ens_wave01[without_outliers_ix_wave01,],
                 ens3 = nbp_ens_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01,col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'NBP', ylim = c(-10,10))

lines(years, nbp_stan, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = cSoil_ens_wave00[without_outliers_ix_wave00,],
                 ens2 = cSoil_ens_wave01[without_outliers_ix_wave01,],
                 ens3 = cSoil_ens_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'cSoil', ylim = range(c(cSoil_ens_wave00[,1], cSoil_ens_wave00[,164])))

lines(years, cSoil_stan, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = cVeg_ens_wave00[without_outliers_ix_wave00,],
                 ens2 = cVeg_ens_wave01[without_outliers_ix_wave01,],
                 ens3 = cVeg_ens_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'cVeg')

lines(years, cVeg_stan, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = lai_lnd_mean_ens_wave00[without_outliers_ix_wave00,],
                 ens2 = lai_lnd_mean_ens_wave01[without_outliers_ix_wave01,],
                 ens3 = lai_lnd_mean_ens_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'Lai')

lines(years, lai_lnd_mean_stan, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = rh_lnd_sum_ens_wave00[without_outliers_ix_wave00,],
                 ens2 = rh_lnd_sum_ens_wave01[without_outliers_ix_wave01,],
                 ens3 = rh_lnd_sum_ens_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01,  col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'RH')

lines(years, rh_lnd_sum_stan, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = fLuc_lnd_sum_ens_wave00[without_outliers_ix_wave00,],
                 ens2 = fLuc_lnd_sum_ens_wave01[without_outliers_ix_wave01,],
                 ens3 = fLuc_lnd_sum_ens_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'fLuc')

lines(years, fLuc_lnd_sum_stan, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = fHarvest_lnd_sum_ens_wave00[without_outliers_ix_wave00,],
                 ens2 = fHarvest_lnd_sum_ens_wave01[without_outliers_ix_wave01,],
                 ens3 = fHarvest_lnd_sum_ens_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'fHarvest')

lines(years, fHarvest_lnd_sum_stan, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = treeFrac_lnd_mean_ens_wave00[without_outliers_ix_wave00,],
                 ens2 = treeFrac_lnd_mean_ens_wave01[without_outliers_ix_wave01,],
                 ens3 = treeFrac_lnd_mean_ens_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = '%', main = 'treefrac'
                 )

lines(years, treeFrac_lnd_mean_stan, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = shrubFrac_lnd_mean_ens_wave00[without_outliers_ix_wave00,],
                 ens2 = shrubFrac_lnd_mean_ens_wave01[without_outliers_ix_wave01,],
                 ens3 = shrubFrac_lnd_mean_ens_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = '%', main = 'shrubfrac'
)

lines(years, shrubFrac_lnd_mean_stan, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = baresoilFrac_lnd_mean_ens_wave00[without_outliers_ix_wave00,],
                 ens2 = baresoilFrac_lnd_mean_ens_wave01[without_outliers_ix_wave01,],
                 ens3 = baresoilFrac_lnd_mean_ens_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = '%', main = 'baresoilfrac')

lines(years, baresoilFrac_lnd_mean_stan, col = stancol, lty = 'solid', lwd = 2)


linePlotMultiEns(years = years, c3PftFrac_lnd_mean_ens_wave00[without_outliers_ix_wave00,],
                 ens2 = c3PftFrac_lnd_mean_ens_wave01[without_outliers_ix_wave01,],
                 ens3 = c3PftFrac_lnd_mean_ens_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = '%', main = 'c3PftFrac')

lines(years, c3PftFrac_lnd_mean_stan, col = stancol, lty = 'solid', lwd = 2)


linePlotMultiEns(years = years, c4PftFrac_lnd_mean_ens_wave00[without_outliers_ix_wave00,],
                 ens2 = c4PftFrac_lnd_mean_ens_wave01[without_outliers_ix_wave01,],
                 ens3 = c4PftFrac_lnd_mean_ens_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = '%', main = 'c3PftFrac')

lines(years, c4PftFrac_lnd_mean_stan, col = stancol, lty = 'solid', lwd = 2)


reset()

legend('bottomright', legend = c('wave00','wave01','wave01 level2','standard'), lty = 'solid', lwd = 1.5, col = c(lcol_wave0, lcol_wave01, lcol_wave01_level2, stancol), inset = c(0.05, 0.15) )


#dev.off()


#pdf(file = 'figs/carbon-cycle-timeseries-anomaly-waves-constrained.pdf', width = 10, height = 12)
par(mfrow= c(3,5), las = 1, mar = c(4,4,1,0))

linePlotMultiEns(years = years, ens1 = npp_ens_anom_wave00[without_outliers_ix_wave00,],
                 ens2 = npp_ens_anom_wave01[without_outliers_ix_wave01,],
                 ens3 = npp_ens_anom_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'NPP')

lines(years,npp_stan_anom, col = stancol, lty = 'solid', lwd = 2)
linePlotMultiEns(years = years, ens1 =  nbp_ens_anom_wave00[without_outliers_ix_wave00,], 
                 ens2 = nbp_ens_anom_wave01[without_outliers_ix_wave01,],
                 ens3 = nbp_ens_anom_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01,col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'NBP', ylim = c(-10,10))

lines(years, nbp_stan_anom, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = cSoil_ens_anom_wave00[without_outliers_ix_wave00,],
                 ens2 = cSoil_ens_anom_wave01[without_outliers_ix_wave01,],
                 ens3 = cSoil_ens_anom_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'cSoil', ylim = range(c(cSoil_ens_anom_wave00[,1], cSoil_ens_anom_wave00[,164])))

lines(years, cSoil_stan_anom, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = cVeg_ens_anom_wave00[without_outliers_ix_wave00,],
                 ens2 = cVeg_ens_anom_wave01[without_outliers_ix_wave01,],
                 ens3 = cVeg_ens_anom_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'cVeg')

lines(years, cVeg_stan_anom, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = lai_lnd_mean_ens_anom_wave00[without_outliers_ix_wave00,],
                 ens2 = lai_lnd_mean_ens_anom_wave01[without_outliers_ix_wave01,],
                 ens3 = lai_lnd_mean_ens_anom_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'Lai')

lines(years, lai_lnd_mean_stan_anom, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = rh_lnd_sum_ens_anom_wave00[without_outliers_ix_wave00,],
                 ens2 = rh_lnd_sum_ens_anom_wave01[without_outliers_ix_wave01,],
                 ens3 = rh_lnd_sum_ens_anom_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01,  col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'RH')

lines(years, rh_lnd_sum_stan_anom, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = fLuc_lnd_sum_ens_anom_wave00[without_outliers_ix_wave00,],
                 ens2 = fLuc_lnd_sum_ens_anom_wave01[without_outliers_ix_wave01,],
                 ens3 = fLuc_lnd_sum_ens_anom_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'fLuc')

lines(years, fLuc_lnd_sum_stan_anom, col = stancol, lty = 'solid', lwd = 2)
 
linePlotMultiEns(years = years, ens1 = fHarvest_lnd_sum_ens_anom_wave00[without_outliers_ix_wave00,],
                 ens2 = fHarvest_lnd_sum_ens_anom_wave01[without_outliers_ix_wave01,],
                 ens3 = fHarvest_lnd_sum_ens_anom_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = 'GtC', main = 'fHarvest')

lines(years, fHarvest_lnd_sum_stan_anom, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = treeFrac_lnd_mean_ens_anom_wave00[without_outliers_ix_wave00,],
                 ens2 = treeFrac_lnd_mean_ens_anom_wave01[without_outliers_ix_wave01,],
                 ens3 = treeFrac_lnd_mean_ens_anom_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = '%', main = 'treefrac'
                 )

lines(years, treeFrac_lnd_mean_stan_anom, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = shrubFrac_lnd_mean_ens_anom_wave00[without_outliers_ix_wave00,],
                 ens2 = shrubFrac_lnd_mean_ens_anom_wave01[without_outliers_ix_wave01,],
                 ens3 = shrubFrac_lnd_mean_ens_anom_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = '%', main = 'shrubfrac'
)

lines(years, shrubFrac_lnd_mean_stan_anom, col = stancol, lty = 'solid', lwd = 2)

linePlotMultiEns(years = years, ens1 = baresoilFrac_lnd_mean_ens_anom_wave00[without_outliers_ix_wave00,],
                 ens2 = baresoilFrac_lnd_mean_ens_anom_wave01[without_outliers_ix_wave01,],
                 ens3 = baresoilFrac_lnd_mean_ens_anom_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = '%', main = 'baresoilfrac')

lines(years, baresoilFrac_lnd_mean_stan_anom, col = stancol, lty = 'solid', lwd = 2)


linePlotMultiEns(years = years, c3PftFrac_lnd_mean_ens_anom_wave00[without_outliers_ix_wave00,],
                 ens2 = c3PftFrac_lnd_mean_ens_anom_wave01[without_outliers_ix_wave01,],
                 ens3 = c3PftFrac_lnd_mean_ens_anom_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = '%', main = 'c3PftFrac')

lines(years, c3PftFrac_lnd_mean_stan_anom, col = stancol, lty = 'solid', lwd = 2)


linePlotMultiEns(years = years, c4PftFrac_lnd_mean_ens_anom_wave00[without_outliers_ix_wave00,],
                 ens2 = c4PftFrac_lnd_mean_ens_anom_wave01[without_outliers_ix_wave01,],
                 ens3 = c4PftFrac_lnd_mean_ens_anom_wave01[level2a_ix_wave01, ],
                 col1 = lcol_wave0, col2 = lcol_wave01, col3 = lcol_wave01_level2,
                 ylab = '%', main = 'c3PftFrac')

lines(years, c4PftFrac_lnd_mean_stan_anom, col = stancol, lty = 'solid', lwd = 2)

reset()

legend('bottomright', legend = c('wave00','wave01','wave01 level2','standard'), lty = 'solid', lwd = 1.5, col = c(lcol_wave0, lcol_wave01, lcol_wave01_level2, stancol), inset = c(0.05, 0.15) )


#dev.off()

1.3 Constraining to level 2 with the emulator

nunif <- 50000
X_unif <- samp_unif(nunif, mins = rep(0,32), maxes = rep(1, 32))
colnames(X_unif) <- colnames(X)

# Can this go in common data? Would be needed for checking emulator fits
# Create fit lists for the combined data wave00 level 1a and wave01
Y_const_level1a_wave01_scaled_list <- mat2list(Y_const_level1a_wave01_scaled)

fit_list_const_level1a_wave01 <- mclapply(X = Y_const_level1a_wave01_scaled_list , FUN = km, formula = ~., design = X_level1a_wave01,
                                   mc.cores = 4, control = list(trace = FALSE))

Y_const_level1a_wave01_scaled_pred <- multiPred(Y = Y_const_level1a_wave01_scaled, Xpred = X_unif, fit_list = fit_list_const_level1a_wave01)


level2_ix_em_unif_wave00_wave01 <- which(Y_const_level1a_wave01_scaled_pred$pred_mean[,'nbp_lnd_sum'] > 0 &
                                           Y_const_level1a_wave01_scaled_pred$pred_mean[,'npp_nlim_lnd_sum'] > 35 & 
                                           Y_const_level1a_wave01_scaled_pred$pred_mean[,'npp_nlim_lnd_sum'] < 80 &
                                           Y_const_level1a_wave01_scaled_pred$pred_mean[,'cSoil_lnd_sum'] > 750 &
                                           Y_const_level1a_wave01_scaled_pred$pred_mean[,'cSoil_lnd_sum'] < 3000 &
                                           Y_const_level1a_wave01_scaled_pred$pred_mean[,'cVeg_lnd_sum'] > 300 & 
                                           Y_const_level1a_wave01_scaled_pred$pred_mean[,'cVeg_lnd_sum'] < 800
)


(length(level2_ix_em_unif_wave00_wave01) / nunif) * 100
[1] 12.014
X_stan_norm <- normalize(matrix(rep(1, 32), nrow = 1), wrt = lhs)

colnames(X_unif) <- 1:32

#pdf(file = 'figs/pairs_level2_ix_em_unif_wave00_wave01.pdf', width = 12, height = 12)

par(oma = c(0,0,0,3), bg = 'white')

panel_hist_local <- function(x, ...)
{
    usr <- par("usr"); on.exit(par(usr))
    par(usr = c(usr[1:2], 0, 1.5) )
    h <- hist(x, plot = FALSE)
    breaks <- h$breaks; nB <- length(breaks)
    y <- h$counts; y <- y/max(y)
    rect(breaks[-nB], 0, breaks[-1], y, col = "cyan", ...)
}

pairs(rbind(X_unif[level2_ix_em_unif_wave00_wave01, ], X_stan_norm),
      gap = 0, lower.panel = NULL, xlim = c(0,1), ylim = c(0,1),
      panel = dfunc_up_truth,
      diag.panel = panel_hist_local,
      cex.labels = 1,
      col.axis = 'white',
      dfunc_col = rb
      )


image.plot(legend.only = TRUE,
           zlim = c(0,1),
           col = rb,
           legend.args = list(text = 'Density of model runs matching the criteria', side = 3, line = 1),
           legend.shrink = 0.6,
           horizontal = TRUE
)

legend('left', legend = paste(1:32, colnames(lhs)), cex = 1, bty = 'n')


#dev.off()
LS0tCnRpdGxlOiAiQ29uc3RyYWluaW5nIHRoZSBjYXJib24gY3ljbGUgaW4gSlVMRVMtRVMtMS4wIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgdG9jX2RlcHRoOiAyCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwotLS0KCgpDb2RlIHRvIHJ1biBhbmFseXNpcyBhbmQgZ2VuZXJhdGUgZmlndXJlcyBmb3IgTWNOZWFsbCBldCBhbC4gKDIwMjM/KSAiQ29uc3RyYWluaW5nIHRoZSBjYXJib24gY3ljbGUgaW4gSlVMRVMtRVMtMS4wIgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzID0gJ2hpZGUnfQojIExvYWQgaGVscGVyIGZ1bmN0aW9ucwoKa25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy5wYXRoID0gImZpZ3MvIiwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmdzID0gRkFMU0UpCgoKYGBgCgpgYGB7cn0KCnNvdXJjZSgiSlVMRVMtRVMtMXAwLWNvbW1vbi1wYWNrYWdlcy5SIikKc291cmNlKCJKVUxFUy1FUy0xcDAtY29tbW9uLWZ1bmN0aW9ucy5SIikKc291cmNlKCJKVUxFUy1FUy0xcDAtY29tbW9uLWRhdGEuUiIpCgpgYGAKCiMjIEZhaWx1cmUgYW5hbHlzaXMKCmBgYHtyIGZhaWx1cmUtcGFpcnMsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMiwgZmlnLnBhdGg9J2ZpZ3MvJywgZGV2PWMoJ3BuZycsICdwZGYnKX0KCgpsb3dfbnBwX2l4IDwtIHdoaWNoKFlbLCducHBfbmxpbV9sbmRfc3VtJ10gPCAxZTUpCiMgY29kZSBmcm9tIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzI4MTgyODcyL2hvdy10by11c2UtZGlmZmVyZW50LXNldHMtb2YtZGF0YS1pbi1sb3dlci1hbmQtdXBwZXItcGFuZWwtb2YtcGFpcnMtZnVuY3Rpb24taW4KCgojWCA8LSBtYXRyaXgocnVuaWYoMzAwKSwgbmNvbD0zKQojWSA8LSBtYXRyaXgoYyhzb3J0KHJ1bmlmKDEwMCwgMCwgMTApKSwgCiMgICAgICAgICAgICAgIHNvcnQocnVuaWYoMTAwLCAwLCAxMCkpLCAKIyAgICAgICAgICAgICAgc29ydChydW5pZigxMDAsIDAsIDEwKSkpLCBuY29sPTMpCgojcGRmKGZpbGUgPSAnZmlncy9ydW4tZmFpbHVyZS1wYWlycy5wZGYnLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMCkKeDEgPC0gWFtsb3dfbnBwX2l4LCBdCngyIDwtIFhfbmxldmVsMAoKWFkgPC0gcmJpbmQoeDEsIHgyKQoKCnBhaXJzKFhZLAogICAgICBsb3dlci5wYW5lbD1mdW5jdGlvbih4LCB5LCAuLi4pIHsKICAgICAgICBYeCA8LSB4W3NlcV9sZW4obnJvdyh4MSkpXSAjIGNvcnJlc3BvbmRzIHRvIFggc3Vic2V0CiAgICAgICAgWHkgPC0geVtzZXFfbGVuKG5yb3coeDEpKV0gIyBjb3JyZXNwb25kcyB0byBYIHN1YnNldAogICAgICAgICN1c3IgPC0gcGFyKCJ1c3IiKTsgb24uZXhpdChwYXIodXNyKSkKICAgICAgICAjcGFyKHVzciA9IGMocmFuZ2UoeDFbLCAtbmNvbCh4MSldKSwgcmFuZ2UoeDFbLCAtMV0pKSkgIyBzZXQgdXAgbGltaXRzCiAgICAgICAgcG9pbnRzKFh4LCBYeSwgY29sID0gemJsdWUsIHBjaCA9IDE5LCBjZXggPSAwLjgpCiAgICAgICAjIGlmKHBhcignbWZnJylbMl0gPT0gMSkgYXhpcygyKSAjIGlmIGxlZnQgcGxvdCwgYWRkIGxlZnQgYXhpcwogICAgICAgICNpZihwYXIoJ21mZycpWzFdID09IG5jb2woeDEpKSBheGlzKDEpICMgaWYgYm90dG9tIHBsb3QgYWRkIGJvdHRvbSBheGlzCiAgICAgIH0sIAogICAgICB1cHBlci5wYW5lbD1mdW5jdGlvbih4LCB5LCAuLi4pIHsKICAgICAgICBZeCA8LSB4Wyhucm93KHgxKSArIDEpOmxlbmd0aCh4KV0gIyBZIHN1YnNldAogICAgICAgIFl5IDwtIHlbKG5yb3coeDEpICsgMSk6bGVuZ3RoKHkpXSAjIFkgc3Vic2V0CiAgICAgICAgCiAgICAgICAgI2NudHIgPC0gb3V0ZXIoWXgsIFl4LCBGVU49JyonKSAjIGFyYml0cmFyeSBmdW5jdGlvbiBmb3IgY29udG91cgogICAgICAgIyB1c3IgPC0gcGFyKCJ1c3IiKTsgb24uZXhpdChwYXIodXNyKSkKICAgICAgICAjcGFyKHVzciA9IGMocmFuZ2UoeDJbLCAtMV0pLCByYW5nZSh4MlssIC1uY29sKHgyKV0pKSkgIyBzZXQgdXAgbGltaXRzCiAgICAgICAgcG9pbnRzKFl4LCBZeSwgY29sID0genJlZCwgcGNoID0gMTksIGNleCA9IDAuOCkKICAgICAgICAjY29udG91cihZeCwgWXksIGNudHIsIGFkZD1UUlVFKQogICAgICAgICNpZihwYXIoJ21mZycpWzJdID09IG5jb2woeDIpKSBheGlzKDQpICMgaWYgcmlnaHQgcGxvdCwgYWRkIHJpZ2h0IGF4aXMKICAgICAgICAjaWYocGFyKCdtZmcnKVsxXSA9PSAxKSBheGlzKDMpICMgaWYgdG9wIHBsb3QsIGFkZCB0b3AgYXhpcwogICAgICB9LCAKICAgICAgI3RpY2s9RkFMU0UsICMgc3VwcHJlc3MgdGhlIGRlZmF1bHQgdGljayBtYXJrcwogICAgICAjbGluZT0xLAogICAgICBnYXAgPSAwLAogICAgICB4bGltID0gYygwLDEpLCB5bGltID0gYygwLDEpLAogICAgICBsYWJlbHMgPSAxOmQsCiAgICAgIG9tYSA9IGMoMiwgMTgsIDIsIDIpKSAjIG1vdmUgdGhlIGRlZmF1bHQgdGljayBsYWJlbHMgb2ZmIHRoZSBwbG90IAoKcmVzZXQoKQoKbGVnZW5kKCdsZWZ0JywgbGVnZW5kID0gcGFzdGUoMTpkLCBjb2xuYW1lcyhsaHMpKSwgY2V4ID0gMS4xLCBidHkgPSAnbicpCmxlZ2VuZCgndG9wbGVmdCcsIHBjaCA9IDE5LCBjb2wgPSBjKCB6cmVkLCB6Ymx1ZSksIGxlZ2VuZCA9IGMoJ2ZhaWxlZCcsICd6ZXJvIGNhcmJvbiBjeWNsZScpLCBidHkgPSAnbicsIGluc2V0ID0gMC4wMiwgY2V4ID0gMS4xICkKCiNkZXYub2ZmKCkKCmBgYAoKIyBWaXN1YWxpc2luZyB0aGUgZW5zZW1ibGUgcmFuZ2UKCkl0J3MgaW1wb3J0YW50IHRvIHJlbWVtYmVyIHRoYXQgdGhlIGRlc2lnbiBvZiB0aGUgZXhwZXJpbWVudCBpcyBtdWx0aXBsaWNhdGlvbiBmYWN0b3JzIG9mIHRoZSBvcmlnaW5hbCBwYXJhbWV0ZXJzLiBUaGlzIG1pZ2h0IGJlIGltcG9ydGFudCBmb3IgdGhlICJob2xkIiB2YWx1ZSBpbiBhIHNlbnNpdGl2aXR5IGFuYWx5c2lzLCBhcyB0aGUgInN0YW5kYXJkIiB2YWx1ZSBhbmQgdGhlIG1lZGlhbiB2YWx1ZSBvZiB0aGUgZW5zZW1ibGUgd2lsbCBub3QgYmUgdGhlIHNhbWUuCgpgYGB7ciwgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodCA9IDh9CgojcGRmKGZpbGUgPSAnZmlncy9saHNfcmFuZ2UucGRmJywgd2lkdGggPSA2LCBoZWlnaHQgPSA4KQpwYXIobGFzID0gMSwgbWFyID0gYyg1LDgsMiwxKSkKbGhzX21pbiA8LSBhcHBseShsaHNfd2F2ZTBfd2F2ZTAxX2FsbCwgMiwgbWluKQpsaHNfbWF4IDwtIGFwcGx5KGxoc193YXZlMF93YXZlMDFfYWxsLDIsIG1heCkKCnBsb3QobGhzX21heCwgMTpkLCB0eXBlID0gJ24nLCB4bGltID0gYygwLDEwKSwgYXhlcyA9IEZBTFNFLCB4bGFiID0gJ211bHRpcGx5aW5nIGZhY3RvcicsIHlsYWIgPSAnJykKCmFibGluZSh2ID0gMCwgbHR5ID0gJ2Rhc2hlZCcsIGNvbCA9ICdncmV5JykKYWJsaW5lKHYgPSAxLCBsdHkgPSAnZGFzaGVkJywgY29sID0gJ3RvbWF0bzInKQoKc2VnbWVudHMoeDAgPSBsaHNfbWluLCB5MCA9IDE6ZCwgeDEgPSBsaHNfbWF4LCB5MSA9IDE6ZCApCnBvaW50cyhsaHNfbWluLCAxOmQsIHBjaCA9IDIwKQpwb2ludHMobGhzX21heCwgMTpkLCBwY2ggPSAyMCkKYXhpcygyLCBhdCA9IDE6ZCwgbGFiZWxzID0gY29sbmFtZXMobGhzKSkKYXhpcygxKQojZGV2Lm9mZigpCgpgYGAKCiMjIFdhdmUwMC9XYXZlMDEgIEVuc2VtYmxlIGJlaGF2aW91ciBpbiBrZXkgKGNvbnN0cmFpbmluZykgb3V0cHV0cy4gCgpHbG9iYWwgbWVhbiBmb3IgdGhlIDIwIHllYXJzIGF0IHRoZSBlbmQgb2YgdGhlIDIwdGggQ2VudHVyeS4gVGhlcmUgaXMgc3RpbGwgYSBzaWduaWZpY2FudCBsb3cgYmlhcyBvbiBjVmVnIG91dHB1dC4KCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gOH0Kd2F2ZTAwY29sIDwtICdza3libHVlMicKd2F2ZTAxY29sIDwtICd0b21hdG8yJwoKd2F2ZTAwY29sIDwtICdkb2RnZXJibHVlMicKd2F2ZTAxY29sIDwtICdmaXJlYnJpY2snCnJhbmdlY29sIDwtICdncmV5JwpgYGAKCgpgYGB7ciwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDggfQojIEhpc3RvZ3JhbSBvZiBsZXZlbCAxIGNvbnN0cmFpbnRzCmhjb2wgPSAnZGFya2dyZXknCmxjb2wgPSAnYmxhY2snCgojcGRmKGZpbGUgPSAnZmlncy9sZXZlbF8yX2NvbnN0cmFpbnRzX2hpc3RzLnBkZicsIHdpZHRoID0gOCwgaGVpZ2h0ID0gOCkKcGFyKG1mcm93ID0gYygyLDIpLCBmZyA9ICdkYXJrZ3JleScsIGxhcyA9IDEsIG9tYSA9IGMoMC4xLCAwLjEsIDQsIDAuMSkpCgp0cnVuYyA8LSBmdW5jdGlvbih4LCB2ZWMpewogIAogIGRhdCA8LSB4W3ggPCBtYXgodmVjKSAmIHggPiBtaW4odmVjKSAgXQogIAogIGRhdAogIAp9CgoKaCA8LSBoaXN0KFlfY29uc3RfbGV2ZWwxYV9zY2FsZWRbLCduYnBfbG5kX3N1bSddLCBtYWluID0gJ05CUCcsIHhsYWIgPSAnR3RDL3llYXInLCBjb2wgPSBtYWtlVHJhbnNwYXJlbnQod2F2ZTAwY29sLDE1MCkpCmhpc3QodHJ1bmMoWV9jb25zdF93YXZlMDFfc2NhbGVkIFssJ25icF9sbmRfc3VtJ10sIGgkYnJlYWtzKSAsCiAgICAgY29sID0gbWFrZVRyYW5zcGFyZW50KHdhdmUwMWNvbCwxNTApICwgYnJlYWtzID0gaCRicmVha3MsIGFkZCA9IFRSVUUpCgpydWcoWV9jb25zdF9zdGFuX3NjYWxlZFsnbmJwX2xuZF9zdW0nXSwgbHdkID0gMikKCnBvbHlnb24oeCA9IGMoMCwgMTAwLCAxMDAsIDApLCB5ID0gYygwLCAwLCAxMDAwLCAxMDAwKSwKICAgICAgICBjb2wgPSBtYWtlVHJhbnNwYXJlbnQocmFuZ2Vjb2wsIDYwKSwKICAgICAgICBib3JkZXIgPSBtYWtlVHJhbnNwYXJlbnQocmFuZ2Vjb2wpKQoKaCA8LSBoaXN0KFlfY29uc3RfbGV2ZWwxYV9zY2FsZWRbLCducHBfbmxpbV9sbmRfc3VtJ10sY29sID0gbWFrZVRyYW5zcGFyZW50KHdhdmUwMGNvbCwxNTApLCBtYWluID0gJ05QUCcsIHhsYWIgPSAnR3RDL3llYXInKQpoaXN0KHRydW5jKFlfY29uc3Rfd2F2ZTAxX3NjYWxlZCBbLCducHBfbmxpbV9sbmRfc3VtJ10sIGgkYnJlYWtzKSAsIAogICAgIGNvbCA9IG1ha2VUcmFuc3BhcmVudCh3YXZlMDFjb2wpICwgYnJlYWtzID0gaCRicmVha3MsIGFkZCA9IFRSVUUpCgpydWcoWV9jb25zdF9zdGFuX3NjYWxlZFsnbnBwX25saW1fbG5kX3N1bSddLCBsd2QgPSAyKQoKcG9seWdvbih4ID0gYygzNSwgODAsIDgwLCAzNSksIHkgPSBjKDAsIDAsIDEwMDAsIDEwMDApLAogICAgICAgIGNvbCA9IG1ha2VUcmFuc3BhcmVudChyYW5nZWNvbCwgNjApLAogICAgICAgIGJvcmRlciA9IG1ha2VUcmFuc3BhcmVudChyYW5nZWNvbCkpCgoKaCA8LSBoaXN0KFlfY29uc3RfbGV2ZWwxYV9zY2FsZWRbLCdjU29pbF9sbmRfc3VtJ10sIGNvbCA9IG1ha2VUcmFuc3BhcmVudCh3YXZlMDBjb2wsMTUwKSwgbWFpbiA9ICdTb2lsIENhcmJvbicsIHhsYWIgPSAnR3RDJykKaGlzdCh0cnVuYyhZX2NvbnN0X3dhdmUwMV9zY2FsZWQgWywnY1NvaWxfbG5kX3N1bSddLCBoJGJyZWFrcykgLCAKICAgICBjb2wgPSBtYWtlVHJhbnNwYXJlbnQod2F2ZTAxY29sLDE1MCkgLCBicmVha3MgPSBoJGJyZWFrcywgYWRkID0gVFJVRSkKCnJ1ZyhZX2NvbnN0X3N0YW5fc2NhbGVkWydjU29pbF9sbmRfc3VtJ10sIGx3ZCA9IDIpCgpwb2x5Z29uKHggPSBjKDc1MCwgMzAwMCwgMzAwMCwgNzUwKSwgeSA9IGMoMCwgMCwgMTAwMCwgMTAwMCksCiAgICAgICAgY29sID0gbWFrZVRyYW5zcGFyZW50KHJhbmdlY29sLCA2MCksCiAgICAgICAgYm9yZGVyID0gbWFrZVRyYW5zcGFyZW50KHJhbmdlY29sKSkKCmggPC0gaGlzdChZX2NvbnN0X2xldmVsMWFfc2NhbGVkWywnY1ZlZ19sbmRfc3VtJ10sIGNvbCA9IG1ha2VUcmFuc3BhcmVudCh3YXZlMDBjb2wsMTUwKSwgbWFpbiA9ICdWZWdldGF0aW9uIENhcmJvbicsIHhsYWIgPSAnR3RDJykKaGlzdCh0cnVuYyhZX2NvbnN0X3dhdmUwMV9zY2FsZWQgWywnY1ZlZ19sbmRfc3VtJ10sIGgkYnJlYWtzKSAsIAogICBjb2wgPSBtYWtlVHJhbnNwYXJlbnQod2F2ZTAxY29sLDE1MCkgICwgYnJlYWtzID0gaCRicmVha3MsIGFkZCA9IFRSVUUpCgpydWcoWV9jb25zdF9zdGFuX3NjYWxlZFsnY1ZlZ19sbmRfc3VtJ10sIGx3ZCA9IDIpCgpwb2x5Z29uKHggPSBjKDMwMCwgODAwLCA4MDAsIDMwMCksIHkgPSBjKDAsIDAsIDEwMDAsIDEwMDApLAogICAgICAgIGNvbCA9IG1ha2VUcmFuc3BhcmVudChyYW5nZWNvbCwgNjApLAogICAgICAgYm9yZGVyID0gIG1ha2VUcmFuc3BhcmVudChyYW5nZWNvbCkpCgoKCnJlc2V0KCkKCmxlZ2VuZCgndG9wJywgaG9yaXogPSBUUlVFLCBmaWxsID0gYyhtYWtlVHJhbnNwYXJlbnQod2F2ZTAwY29sLCAxNTApLCBtYWtlVHJhbnNwYXJlbnQod2F2ZTAxY29sLCAxNTApLCBtYWtlVHJhbnNwYXJlbnQocmFuZ2Vjb2wsIDYwKSksIGxlZ2VuZCA9IGMoJ1dhdmUwMCcsICdXYXZlMDEnLCAnQVcgcmFuZ2UnKSkKCiNkZXYub2ZmKCkKYGBgCgojIyBXaGF0IHByb3BvcnRpb24gb2Ygd2F2ZTAxIGZhbGwgd2l0aGluIEFuZHkgV2lsdHNoaXJlJ3MgY29uc3RyYWludHM/CgpKdXN0IHVuZGVyIGEgdGhpcmQuIFBvaW50cyBhdCBhIHNpZ25pZmljYW50IG1vZGVsIGRpc2NyZXBlbmN5IGluIGNWZWcKCk9mIHRoZSA0MDAgbWVtYmVycyBvZiB0aGUgd2F2ZTAxIGVuc2VtYmxlLCAxMjggcGFzcyBBbmR5IFdpbHRzaGlyZSdzIExldmVsIDIgY29uc3RyYWludHMuCgpgYGB7cn0KCmxlbmd0aChsZXZlbDJfaXhfd2F2ZTAxKQpsZW5ndGgobGV2ZWwyX2l4X3dhdmUwMSkgLyBudHJhaW5fd2F2ZTAxCgoKYGBgCgoKCmBgYHtyIHBsb3QtY2FyYm9uLWN5Y2xlLXRpbWVzZXJpZXMtcHJpbWFyeSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSAxMn0KCmxjb2xfd2F2ZTAgPC0gbWFrZVRyYW5zcGFyZW50KCdkb2RnZXJibHVlMicsICAxMjApCmxjb2xfd2F2ZTAxIDwtIG1ha2VUcmFuc3BhcmVudCgnZmlyZWJyaWNrJywgIDEyMCkKbGNvbF93YXZlMDFfbGV2ZWwyIDwtICdnb2xkJwpzdGFuY29sID0gJ2JsYWNrJwoKbGluZVBsb3RNdWx0aUVucyA8LSBmdW5jdGlvbih5ZWFycywgZW5zMSwgZW5zMiwgZW5zMywgY29sMSwgY29sMiwgY29sMywgeWxhYiwgbWFpbiwgeWxpbSA9IE5VTEwpewogICMgUGxvdCB3YXZlMDAgYW5kIHdhdmUwMSB0aW1lc2VyaWVzIG9uIHRvcCBvZiBvbmUgYW5vdGhlcgogIAogIG50IDwtIGxlbmd0aCh5ZWFycykgCiAgaWYoaXMubnVsbCh5bGltKSl7CiAgICAKICB5bGltID0gcmFuZ2UoYyhlbnMxWywxXSwgZW5zMVssbnRdLCBlbnMyWywxXSwgZW5zMlsgLG50XSwgZW5zM1ssMV0sIGVuczNbLCBudF0pKQogIH0KICAKICBlbHNlIHlsaW0gPC0geWxpbQogIAogIG1hdHBsb3QoeWVhcnMsIHQoZW5zMSksIHR5cGUgPSAnbCcsIGx0eSA9ICdzb2xpZCcseWxpbSA9IHlsaW0sIGNvbCA9IGNvbDEsCiAgICAgICAgeWxhYiA9IHlsYWIsIG1haW4gPSBtYWluLCB4bGFiID0gJycsCiAgICAgICAgYnR5ID0gJ24nKQogIG1hdGxpbmVzKHllYXJzLCB0KGVuczIpLCBjb2wgPSBjb2wyLCBsdHkgPSAnc29saWQnKQogICAgbWF0bGluZXMoeWVhcnMsIHQoZW5zMyksIGNvbCA9IGNvbDMsIGx0eSA9ICdzb2xpZCcpCn0KCiNwZGYoZmlsZSA9ICdmaWdzL2NhcmJvbi1jeWNsZS10aW1lc2VyaWVzLXdhdmVzLWNvbnN0cmFpbmVkLnBkZicsIHdpZHRoID0gMTAsIGhlaWdodCA9IDEyKQpwYXIobWZyb3c9IGMoMyw1KSwgbGFzID0gMSwgbWFyID0gYyg0LDQsMSwwKSkKCmxpbmVQbG90TXVsdGlFbnMoeWVhcnMgPSB5ZWFycywgZW5zMSA9IG5wcF9lbnNfd2F2ZTAwW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAwLF0sCiAgICAgICAgICAgICAgICAgZW5zMiA9IG5wcF9lbnNfd2F2ZTAxW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAxLF0sCiAgICAgICAgICAgICAgICAgZW5zMyA9IG5wcF9lbnNfd2F2ZTAxW2xldmVsMmFfaXhfd2F2ZTAxLCBdLAogICAgICAgICAgICAgICAgIGNvbDEgPSBsY29sX3dhdmUwLCBjb2wyID0gbGNvbF93YXZlMDEsIGNvbDMgPSBsY29sX3dhdmUwMV9sZXZlbDIsCiAgICAgICAgICAgICAgICAgeWxhYiA9ICdHdEMnLCBtYWluID0gJ05QUCcpCgpsaW5lcyh5ZWFycyxucHBfc3RhbiwgY29sID0gc3RhbmNvbCwgbHR5ID0gJ3NvbGlkJywgbHdkID0gMikKCmxpbmVQbG90TXVsdGlFbnMoeWVhcnMgPSB5ZWFycywgZW5zMSA9ICBuYnBfZW5zX3dhdmUwMFt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMCxdLCAKICAgICAgICAgICAgICAgICBlbnMyID0gbmJwX2Vuc193YXZlMDFbd2l0aG91dF9vdXRsaWVyc19peF93YXZlMDEsXSwKICAgICAgICAgICAgICAgICBlbnMzID0gbmJwX2Vuc193YXZlMDFbbGV2ZWwyYV9peF93YXZlMDEsIF0sCiAgICAgICAgICAgICAgICAgY29sMSA9IGxjb2xfd2F2ZTAsIGNvbDIgPSBsY29sX3dhdmUwMSxjb2wzID0gbGNvbF93YXZlMDFfbGV2ZWwyLAogICAgICAgICAgICAgICAgIHlsYWIgPSAnR3RDJywgbWFpbiA9ICdOQlAnLCB5bGltID0gYygtMTAsMTApKQoKbGluZXMoeWVhcnMsIG5icF9zdGFuLCBjb2wgPSBzdGFuY29sLCBsdHkgPSAnc29saWQnLCBsd2QgPSAyKQoKbGluZVBsb3RNdWx0aUVucyh5ZWFycyA9IHllYXJzLCBlbnMxID0gY1NvaWxfZW5zX3dhdmUwMFt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMCxdLAogICAgICAgICAgICAgICAgIGVuczIgPSBjU29pbF9lbnNfd2F2ZTAxW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAxLF0sCiAgICAgICAgICAgICAgICAgZW5zMyA9IGNTb2lsX2Vuc193YXZlMDFbbGV2ZWwyYV9peF93YXZlMDEsIF0sCiAgICAgICAgICAgICAgICAgY29sMSA9IGxjb2xfd2F2ZTAsIGNvbDIgPSBsY29sX3dhdmUwMSwgY29sMyA9IGxjb2xfd2F2ZTAxX2xldmVsMiwKICAgICAgICAgICAgICAgICB5bGFiID0gJ0d0QycsIG1haW4gPSAnY1NvaWwnLCB5bGltID0gcmFuZ2UoYyhjU29pbF9lbnNfd2F2ZTAwWywxXSwgY1NvaWxfZW5zX3dhdmUwMFssMTY0XSkpKQoKbGluZXMoeWVhcnMsIGNTb2lsX3N0YW4sIGNvbCA9IHN0YW5jb2wsIGx0eSA9ICdzb2xpZCcsIGx3ZCA9IDIpCgpsaW5lUGxvdE11bHRpRW5zKHllYXJzID0geWVhcnMsIGVuczEgPSBjVmVnX2Vuc193YXZlMDBbd2l0aG91dF9vdXRsaWVyc19peF93YXZlMDAsXSwKICAgICAgICAgICAgICAgICBlbnMyID0gY1ZlZ19lbnNfd2F2ZTAxW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAxLF0sCiAgICAgICAgICAgICAgICAgZW5zMyA9IGNWZWdfZW5zX3dhdmUwMVtsZXZlbDJhX2l4X3dhdmUwMSwgXSwKICAgICAgICAgICAgICAgICBjb2wxID0gbGNvbF93YXZlMCwgY29sMiA9IGxjb2xfd2F2ZTAxLCBjb2wzID0gbGNvbF93YXZlMDFfbGV2ZWwyLAogICAgICAgICAgICAgICAgIHlsYWIgPSAnR3RDJywgbWFpbiA9ICdjVmVnJykKCmxpbmVzKHllYXJzLCBjVmVnX3N0YW4sIGNvbCA9IHN0YW5jb2wsIGx0eSA9ICdzb2xpZCcsIGx3ZCA9IDIpCgpsaW5lUGxvdE11bHRpRW5zKHllYXJzID0geWVhcnMsIGVuczEgPSBsYWlfbG5kX21lYW5fZW5zX3dhdmUwMFt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMCxdLAogICAgICAgICAgICAgICAgIGVuczIgPSBsYWlfbG5kX21lYW5fZW5zX3dhdmUwMVt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMSxdLAogICAgICAgICAgICAgICAgIGVuczMgPSBsYWlfbG5kX21lYW5fZW5zX3dhdmUwMVtsZXZlbDJhX2l4X3dhdmUwMSwgXSwKICAgICAgICAgICAgICAgICBjb2wxID0gbGNvbF93YXZlMCwgY29sMiA9IGxjb2xfd2F2ZTAxLCBjb2wzID0gbGNvbF93YXZlMDFfbGV2ZWwyLAogICAgICAgICAgICAgICAgIHlsYWIgPSAnR3RDJywgbWFpbiA9ICdMYWknKQoKbGluZXMoeWVhcnMsIGxhaV9sbmRfbWVhbl9zdGFuLCBjb2wgPSBzdGFuY29sLCBsdHkgPSAnc29saWQnLCBsd2QgPSAyKQoKbGluZVBsb3RNdWx0aUVucyh5ZWFycyA9IHllYXJzLCBlbnMxID0gcmhfbG5kX3N1bV9lbnNfd2F2ZTAwW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAwLF0sCiAgICAgICAgICAgICAgICAgZW5zMiA9IHJoX2xuZF9zdW1fZW5zX3dhdmUwMVt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMSxdLAogICAgICAgICAgICAgICAgIGVuczMgPSByaF9sbmRfc3VtX2Vuc193YXZlMDFbbGV2ZWwyYV9peF93YXZlMDEsIF0sCiAgICAgICAgICAgICAgICAgY29sMSA9IGxjb2xfd2F2ZTAsIGNvbDIgPSBsY29sX3dhdmUwMSwgIGNvbDMgPSBsY29sX3dhdmUwMV9sZXZlbDIsCiAgICAgICAgICAgICAgICAgeWxhYiA9ICdHdEMnLCBtYWluID0gJ1JIJykKCmxpbmVzKHllYXJzLCByaF9sbmRfc3VtX3N0YW4sIGNvbCA9IHN0YW5jb2wsIGx0eSA9ICdzb2xpZCcsIGx3ZCA9IDIpCgpsaW5lUGxvdE11bHRpRW5zKHllYXJzID0geWVhcnMsIGVuczEgPSBmTHVjX2xuZF9zdW1fZW5zX3dhdmUwMFt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMCxdLAogICAgICAgICAgICAgICAgIGVuczIgPSBmTHVjX2xuZF9zdW1fZW5zX3dhdmUwMVt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMSxdLAogICAgICAgICAgICAgICAgIGVuczMgPSBmTHVjX2xuZF9zdW1fZW5zX3dhdmUwMVtsZXZlbDJhX2l4X3dhdmUwMSwgXSwKICAgICAgICAgICAgICAgICBjb2wxID0gbGNvbF93YXZlMCwgY29sMiA9IGxjb2xfd2F2ZTAxLCBjb2wzID0gbGNvbF93YXZlMDFfbGV2ZWwyLAogICAgICAgICAgICAgICAgIHlsYWIgPSAnR3RDJywgbWFpbiA9ICdmTHVjJykKCmxpbmVzKHllYXJzLCBmTHVjX2xuZF9zdW1fc3RhbiwgY29sID0gc3RhbmNvbCwgbHR5ID0gJ3NvbGlkJywgbHdkID0gMikKCmxpbmVQbG90TXVsdGlFbnMoeWVhcnMgPSB5ZWFycywgZW5zMSA9IGZIYXJ2ZXN0X2xuZF9zdW1fZW5zX3dhdmUwMFt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMCxdLAogICAgICAgICAgICAgICAgIGVuczIgPSBmSGFydmVzdF9sbmRfc3VtX2Vuc193YXZlMDFbd2l0aG91dF9vdXRsaWVyc19peF93YXZlMDEsXSwKICAgICAgICAgICAgICAgICBlbnMzID0gZkhhcnZlc3RfbG5kX3N1bV9lbnNfd2F2ZTAxW2xldmVsMmFfaXhfd2F2ZTAxLCBdLAogICAgICAgICAgICAgICAgIGNvbDEgPSBsY29sX3dhdmUwLCBjb2wyID0gbGNvbF93YXZlMDEsIGNvbDMgPSBsY29sX3dhdmUwMV9sZXZlbDIsCiAgICAgICAgICAgICAgICAgeWxhYiA9ICdHdEMnLCBtYWluID0gJ2ZIYXJ2ZXN0JykKCmxpbmVzKHllYXJzLCBmSGFydmVzdF9sbmRfc3VtX3N0YW4sIGNvbCA9IHN0YW5jb2wsIGx0eSA9ICdzb2xpZCcsIGx3ZCA9IDIpCgpsaW5lUGxvdE11bHRpRW5zKHllYXJzID0geWVhcnMsIGVuczEgPSB0cmVlRnJhY19sbmRfbWVhbl9lbnNfd2F2ZTAwW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAwLF0sCiAgICAgICAgICAgICAgICAgZW5zMiA9IHRyZWVGcmFjX2xuZF9tZWFuX2Vuc193YXZlMDFbd2l0aG91dF9vdXRsaWVyc19peF93YXZlMDEsXSwKICAgICAgICAgICAgICAgICBlbnMzID0gdHJlZUZyYWNfbG5kX21lYW5fZW5zX3dhdmUwMVtsZXZlbDJhX2l4X3dhdmUwMSwgXSwKICAgICAgICAgICAgICAgICBjb2wxID0gbGNvbF93YXZlMCwgY29sMiA9IGxjb2xfd2F2ZTAxLCBjb2wzID0gbGNvbF93YXZlMDFfbGV2ZWwyLAogICAgICAgICAgICAgICAgIHlsYWIgPSAnJScsIG1haW4gPSAndHJlZWZyYWMnCiAgICAgICAgICAgICAgICAgKQoKbGluZXMoeWVhcnMsIHRyZWVGcmFjX2xuZF9tZWFuX3N0YW4sIGNvbCA9IHN0YW5jb2wsIGx0eSA9ICdzb2xpZCcsIGx3ZCA9IDIpCgpsaW5lUGxvdE11bHRpRW5zKHllYXJzID0geWVhcnMsIGVuczEgPSBzaHJ1YkZyYWNfbG5kX21lYW5fZW5zX3dhdmUwMFt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMCxdLAogICAgICAgICAgICAgICAgIGVuczIgPSBzaHJ1YkZyYWNfbG5kX21lYW5fZW5zX3dhdmUwMVt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMSxdLAogICAgICAgICAgICAgICAgIGVuczMgPSBzaHJ1YkZyYWNfbG5kX21lYW5fZW5zX3dhdmUwMVtsZXZlbDJhX2l4X3dhdmUwMSwgXSwKICAgICAgICAgICAgICAgICBjb2wxID0gbGNvbF93YXZlMCwgY29sMiA9IGxjb2xfd2F2ZTAxLCBjb2wzID0gbGNvbF93YXZlMDFfbGV2ZWwyLAogICAgICAgICAgICAgICAgIHlsYWIgPSAnJScsIG1haW4gPSAnc2hydWJmcmFjJwopCgpsaW5lcyh5ZWFycywgc2hydWJGcmFjX2xuZF9tZWFuX3N0YW4sIGNvbCA9IHN0YW5jb2wsIGx0eSA9ICdzb2xpZCcsIGx3ZCA9IDIpCgpsaW5lUGxvdE11bHRpRW5zKHllYXJzID0geWVhcnMsIGVuczEgPSBiYXJlc29pbEZyYWNfbG5kX21lYW5fZW5zX3dhdmUwMFt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMCxdLAogICAgICAgICAgICAgICAgIGVuczIgPSBiYXJlc29pbEZyYWNfbG5kX21lYW5fZW5zX3dhdmUwMVt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMSxdLAogICAgICAgICAgICAgICAgIGVuczMgPSBiYXJlc29pbEZyYWNfbG5kX21lYW5fZW5zX3dhdmUwMVtsZXZlbDJhX2l4X3dhdmUwMSwgXSwKICAgICAgICAgICAgICAgICBjb2wxID0gbGNvbF93YXZlMCwgY29sMiA9IGxjb2xfd2F2ZTAxLCBjb2wzID0gbGNvbF93YXZlMDFfbGV2ZWwyLAogICAgICAgICAgICAgICAgIHlsYWIgPSAnJScsIG1haW4gPSAnYmFyZXNvaWxmcmFjJykKCmxpbmVzKHllYXJzLCBiYXJlc29pbEZyYWNfbG5kX21lYW5fc3RhbiwgY29sID0gc3RhbmNvbCwgbHR5ID0gJ3NvbGlkJywgbHdkID0gMikKCgpsaW5lUGxvdE11bHRpRW5zKHllYXJzID0geWVhcnMsIGMzUGZ0RnJhY19sbmRfbWVhbl9lbnNfd2F2ZTAwW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAwLF0sCiAgICAgICAgICAgICAgICAgZW5zMiA9IGMzUGZ0RnJhY19sbmRfbWVhbl9lbnNfd2F2ZTAxW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAxLF0sCiAgICAgICAgICAgICAgICAgZW5zMyA9IGMzUGZ0RnJhY19sbmRfbWVhbl9lbnNfd2F2ZTAxW2xldmVsMmFfaXhfd2F2ZTAxLCBdLAogICAgICAgICAgICAgICAgIGNvbDEgPSBsY29sX3dhdmUwLCBjb2wyID0gbGNvbF93YXZlMDEsIGNvbDMgPSBsY29sX3dhdmUwMV9sZXZlbDIsCiAgICAgICAgICAgICAgICAgeWxhYiA9ICclJywgbWFpbiA9ICdjM1BmdEZyYWMnKQoKbGluZXMoeWVhcnMsIGMzUGZ0RnJhY19sbmRfbWVhbl9zdGFuLCBjb2wgPSBzdGFuY29sLCBsdHkgPSAnc29saWQnLCBsd2QgPSAyKQoKCmxpbmVQbG90TXVsdGlFbnMoeWVhcnMgPSB5ZWFycywgYzRQZnRGcmFjX2xuZF9tZWFuX2Vuc193YXZlMDBbd2l0aG91dF9vdXRsaWVyc19peF93YXZlMDAsXSwKICAgICAgICAgICAgICAgICBlbnMyID0gYzRQZnRGcmFjX2xuZF9tZWFuX2Vuc193YXZlMDFbd2l0aG91dF9vdXRsaWVyc19peF93YXZlMDEsXSwKICAgICAgICAgICAgICAgICBlbnMzID0gYzRQZnRGcmFjX2xuZF9tZWFuX2Vuc193YXZlMDFbbGV2ZWwyYV9peF93YXZlMDEsIF0sCiAgICAgICAgICAgICAgICAgY29sMSA9IGxjb2xfd2F2ZTAsIGNvbDIgPSBsY29sX3dhdmUwMSwgY29sMyA9IGxjb2xfd2F2ZTAxX2xldmVsMiwKICAgICAgICAgICAgICAgICB5bGFiID0gJyUnLCBtYWluID0gJ2MzUGZ0RnJhYycpCgpsaW5lcyh5ZWFycywgYzRQZnRGcmFjX2xuZF9tZWFuX3N0YW4sIGNvbCA9IHN0YW5jb2wsIGx0eSA9ICdzb2xpZCcsIGx3ZCA9IDIpCgoKcmVzZXQoKQoKbGVnZW5kKCdib3R0b21yaWdodCcsIGxlZ2VuZCA9IGMoJ3dhdmUwMCcsJ3dhdmUwMScsJ3dhdmUwMSBsZXZlbDInLCdzdGFuZGFyZCcpLCBsdHkgPSAnc29saWQnLCBsd2QgPSAxLjUsIGNvbCA9IGMobGNvbF93YXZlMCwgbGNvbF93YXZlMDEsIGxjb2xfd2F2ZTAxX2xldmVsMiwgc3RhbmNvbCksIGluc2V0ID0gYygwLjA1LCAwLjE1KSApCgojZGV2Lm9mZigpCmBgYApgYGB7ciwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSAxMn0KCgojcGRmKGZpbGUgPSAnZmlncy9jYXJib24tY3ljbGUtdGltZXNlcmllcy1hbm9tYWx5LXdhdmVzLWNvbnN0cmFpbmVkLnBkZicsIHdpZHRoID0gMTAsIGhlaWdodCA9IDEyKQpwYXIobWZyb3c9IGMoMyw1KSwgbGFzID0gMSwgbWFyID0gYyg0LDQsMSwwKSkKCmxpbmVQbG90TXVsdGlFbnMoeWVhcnMgPSB5ZWFycywgZW5zMSA9IG5wcF9lbnNfYW5vbV93YXZlMDBbd2l0aG91dF9vdXRsaWVyc19peF93YXZlMDAsXSwKICAgICAgICAgICAgICAgICBlbnMyID0gbnBwX2Vuc19hbm9tX3dhdmUwMVt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMSxdLAogICAgICAgICAgICAgICAgIGVuczMgPSBucHBfZW5zX2Fub21fd2F2ZTAxW2xldmVsMmFfaXhfd2F2ZTAxLCBdLAogICAgICAgICAgICAgICAgIGNvbDEgPSBsY29sX3dhdmUwLCBjb2wyID0gbGNvbF93YXZlMDEsIGNvbDMgPSBsY29sX3dhdmUwMV9sZXZlbDIsCiAgICAgICAgICAgICAgICAgeWxhYiA9ICdHdEMnLCBtYWluID0gJ05QUCcpCgpsaW5lcyh5ZWFycyxucHBfc3Rhbl9hbm9tLCBjb2wgPSBzdGFuY29sLCBsdHkgPSAnc29saWQnLCBsd2QgPSAyKQpsaW5lUGxvdE11bHRpRW5zKHllYXJzID0geWVhcnMsIGVuczEgPSAgbmJwX2Vuc19hbm9tX3dhdmUwMFt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMCxdLCAKICAgICAgICAgICAgICAgICBlbnMyID0gbmJwX2Vuc19hbm9tX3dhdmUwMVt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMSxdLAogICAgICAgICAgICAgICAgIGVuczMgPSBuYnBfZW5zX2Fub21fd2F2ZTAxW2xldmVsMmFfaXhfd2F2ZTAxLCBdLAogICAgICAgICAgICAgICAgIGNvbDEgPSBsY29sX3dhdmUwLCBjb2wyID0gbGNvbF93YXZlMDEsY29sMyA9IGxjb2xfd2F2ZTAxX2xldmVsMiwKICAgICAgICAgICAgICAgICB5bGFiID0gJ0d0QycsIG1haW4gPSAnTkJQJywgeWxpbSA9IGMoLTEwLDEwKSkKCmxpbmVzKHllYXJzLCBuYnBfc3Rhbl9hbm9tLCBjb2wgPSBzdGFuY29sLCBsdHkgPSAnc29saWQnLCBsd2QgPSAyKQoKbGluZVBsb3RNdWx0aUVucyh5ZWFycyA9IHllYXJzLCBlbnMxID0gY1NvaWxfZW5zX2Fub21fd2F2ZTAwW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAwLF0sCiAgICAgICAgICAgICAgICAgZW5zMiA9IGNTb2lsX2Vuc19hbm9tX3dhdmUwMVt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMSxdLAogICAgICAgICAgICAgICAgIGVuczMgPSBjU29pbF9lbnNfYW5vbV93YXZlMDFbbGV2ZWwyYV9peF93YXZlMDEsIF0sCiAgICAgICAgICAgICAgICAgY29sMSA9IGxjb2xfd2F2ZTAsIGNvbDIgPSBsY29sX3dhdmUwMSwgY29sMyA9IGxjb2xfd2F2ZTAxX2xldmVsMiwKICAgICAgICAgICAgICAgICB5bGFiID0gJ0d0QycsIG1haW4gPSAnY1NvaWwnLCB5bGltID0gcmFuZ2UoYyhjU29pbF9lbnNfYW5vbV93YXZlMDBbLDFdLCBjU29pbF9lbnNfYW5vbV93YXZlMDBbLDE2NF0pKSkKCmxpbmVzKHllYXJzLCBjU29pbF9zdGFuX2Fub20sIGNvbCA9IHN0YW5jb2wsIGx0eSA9ICdzb2xpZCcsIGx3ZCA9IDIpCgpsaW5lUGxvdE11bHRpRW5zKHllYXJzID0geWVhcnMsIGVuczEgPSBjVmVnX2Vuc19hbm9tX3dhdmUwMFt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMCxdLAogICAgICAgICAgICAgICAgIGVuczIgPSBjVmVnX2Vuc19hbm9tX3dhdmUwMVt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMSxdLAogICAgICAgICAgICAgICAgIGVuczMgPSBjVmVnX2Vuc19hbm9tX3dhdmUwMVtsZXZlbDJhX2l4X3dhdmUwMSwgXSwKICAgICAgICAgICAgICAgICBjb2wxID0gbGNvbF93YXZlMCwgY29sMiA9IGxjb2xfd2F2ZTAxLCBjb2wzID0gbGNvbF93YXZlMDFfbGV2ZWwyLAogICAgICAgICAgICAgICAgIHlsYWIgPSAnR3RDJywgbWFpbiA9ICdjVmVnJykKCmxpbmVzKHllYXJzLCBjVmVnX3N0YW5fYW5vbSwgY29sID0gc3RhbmNvbCwgbHR5ID0gJ3NvbGlkJywgbHdkID0gMikKCmxpbmVQbG90TXVsdGlFbnMoeWVhcnMgPSB5ZWFycywgZW5zMSA9IGxhaV9sbmRfbWVhbl9lbnNfYW5vbV93YXZlMDBbd2l0aG91dF9vdXRsaWVyc19peF93YXZlMDAsXSwKICAgICAgICAgICAgICAgICBlbnMyID0gbGFpX2xuZF9tZWFuX2Vuc19hbm9tX3dhdmUwMVt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMSxdLAogICAgICAgICAgICAgICAgIGVuczMgPSBsYWlfbG5kX21lYW5fZW5zX2Fub21fd2F2ZTAxW2xldmVsMmFfaXhfd2F2ZTAxLCBdLAogICAgICAgICAgICAgICAgIGNvbDEgPSBsY29sX3dhdmUwLCBjb2wyID0gbGNvbF93YXZlMDEsIGNvbDMgPSBsY29sX3dhdmUwMV9sZXZlbDIsCiAgICAgICAgICAgICAgICAgeWxhYiA9ICdHdEMnLCBtYWluID0gJ0xhaScpCgpsaW5lcyh5ZWFycywgbGFpX2xuZF9tZWFuX3N0YW5fYW5vbSwgY29sID0gc3RhbmNvbCwgbHR5ID0gJ3NvbGlkJywgbHdkID0gMikKCmxpbmVQbG90TXVsdGlFbnMoeWVhcnMgPSB5ZWFycywgZW5zMSA9IHJoX2xuZF9zdW1fZW5zX2Fub21fd2F2ZTAwW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAwLF0sCiAgICAgICAgICAgICAgICAgZW5zMiA9IHJoX2xuZF9zdW1fZW5zX2Fub21fd2F2ZTAxW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAxLF0sCiAgICAgICAgICAgICAgICAgZW5zMyA9IHJoX2xuZF9zdW1fZW5zX2Fub21fd2F2ZTAxW2xldmVsMmFfaXhfd2F2ZTAxLCBdLAogICAgICAgICAgICAgICAgIGNvbDEgPSBsY29sX3dhdmUwLCBjb2wyID0gbGNvbF93YXZlMDEsICBjb2wzID0gbGNvbF93YXZlMDFfbGV2ZWwyLAogICAgICAgICAgICAgICAgIHlsYWIgPSAnR3RDJywgbWFpbiA9ICdSSCcpCgpsaW5lcyh5ZWFycywgcmhfbG5kX3N1bV9zdGFuX2Fub20sIGNvbCA9IHN0YW5jb2wsIGx0eSA9ICdzb2xpZCcsIGx3ZCA9IDIpCgpsaW5lUGxvdE11bHRpRW5zKHllYXJzID0geWVhcnMsIGVuczEgPSBmTHVjX2xuZF9zdW1fZW5zX2Fub21fd2F2ZTAwW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAwLF0sCiAgICAgICAgICAgICAgICAgZW5zMiA9IGZMdWNfbG5kX3N1bV9lbnNfYW5vbV93YXZlMDFbd2l0aG91dF9vdXRsaWVyc19peF93YXZlMDEsXSwKICAgICAgICAgICAgICAgICBlbnMzID0gZkx1Y19sbmRfc3VtX2Vuc19hbm9tX3dhdmUwMVtsZXZlbDJhX2l4X3dhdmUwMSwgXSwKICAgICAgICAgICAgICAgICBjb2wxID0gbGNvbF93YXZlMCwgY29sMiA9IGxjb2xfd2F2ZTAxLCBjb2wzID0gbGNvbF93YXZlMDFfbGV2ZWwyLAogICAgICAgICAgICAgICAgIHlsYWIgPSAnR3RDJywgbWFpbiA9ICdmTHVjJykKCmxpbmVzKHllYXJzLCBmTHVjX2xuZF9zdW1fc3Rhbl9hbm9tLCBjb2wgPSBzdGFuY29sLCBsdHkgPSAnc29saWQnLCBsd2QgPSAyKQogCmxpbmVQbG90TXVsdGlFbnMoeWVhcnMgPSB5ZWFycywgZW5zMSA9IGZIYXJ2ZXN0X2xuZF9zdW1fZW5zX2Fub21fd2F2ZTAwW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAwLF0sCiAgICAgICAgICAgICAgICAgZW5zMiA9IGZIYXJ2ZXN0X2xuZF9zdW1fZW5zX2Fub21fd2F2ZTAxW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAxLF0sCiAgICAgICAgICAgICAgICAgZW5zMyA9IGZIYXJ2ZXN0X2xuZF9zdW1fZW5zX2Fub21fd2F2ZTAxW2xldmVsMmFfaXhfd2F2ZTAxLCBdLAogICAgICAgICAgICAgICAgIGNvbDEgPSBsY29sX3dhdmUwLCBjb2wyID0gbGNvbF93YXZlMDEsIGNvbDMgPSBsY29sX3dhdmUwMV9sZXZlbDIsCiAgICAgICAgICAgICAgICAgeWxhYiA9ICdHdEMnLCBtYWluID0gJ2ZIYXJ2ZXN0JykKCmxpbmVzKHllYXJzLCBmSGFydmVzdF9sbmRfc3VtX3N0YW5fYW5vbSwgY29sID0gc3RhbmNvbCwgbHR5ID0gJ3NvbGlkJywgbHdkID0gMikKCmxpbmVQbG90TXVsdGlFbnMoeWVhcnMgPSB5ZWFycywgZW5zMSA9IHRyZWVGcmFjX2xuZF9tZWFuX2Vuc19hbm9tX3dhdmUwMFt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMCxdLAogICAgICAgICAgICAgICAgIGVuczIgPSB0cmVlRnJhY19sbmRfbWVhbl9lbnNfYW5vbV93YXZlMDFbd2l0aG91dF9vdXRsaWVyc19peF93YXZlMDEsXSwKICAgICAgICAgICAgICAgICBlbnMzID0gdHJlZUZyYWNfbG5kX21lYW5fZW5zX2Fub21fd2F2ZTAxW2xldmVsMmFfaXhfd2F2ZTAxLCBdLAogICAgICAgICAgICAgICAgIGNvbDEgPSBsY29sX3dhdmUwLCBjb2wyID0gbGNvbF93YXZlMDEsIGNvbDMgPSBsY29sX3dhdmUwMV9sZXZlbDIsCiAgICAgICAgICAgICAgICAgeWxhYiA9ICclJywgbWFpbiA9ICd0cmVlZnJhYycKICAgICAgICAgICAgICAgICApCgpsaW5lcyh5ZWFycywgdHJlZUZyYWNfbG5kX21lYW5fc3Rhbl9hbm9tLCBjb2wgPSBzdGFuY29sLCBsdHkgPSAnc29saWQnLCBsd2QgPSAyKQoKbGluZVBsb3RNdWx0aUVucyh5ZWFycyA9IHllYXJzLCBlbnMxID0gc2hydWJGcmFjX2xuZF9tZWFuX2Vuc19hbm9tX3dhdmUwMFt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMCxdLAogICAgICAgICAgICAgICAgIGVuczIgPSBzaHJ1YkZyYWNfbG5kX21lYW5fZW5zX2Fub21fd2F2ZTAxW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAxLF0sCiAgICAgICAgICAgICAgICAgZW5zMyA9IHNocnViRnJhY19sbmRfbWVhbl9lbnNfYW5vbV93YXZlMDFbbGV2ZWwyYV9peF93YXZlMDEsIF0sCiAgICAgICAgICAgICAgICAgY29sMSA9IGxjb2xfd2F2ZTAsIGNvbDIgPSBsY29sX3dhdmUwMSwgY29sMyA9IGxjb2xfd2F2ZTAxX2xldmVsMiwKICAgICAgICAgICAgICAgICB5bGFiID0gJyUnLCBtYWluID0gJ3NocnViZnJhYycKKQoKbGluZXMoeWVhcnMsIHNocnViRnJhY19sbmRfbWVhbl9zdGFuX2Fub20sIGNvbCA9IHN0YW5jb2wsIGx0eSA9ICdzb2xpZCcsIGx3ZCA9IDIpCgpsaW5lUGxvdE11bHRpRW5zKHllYXJzID0geWVhcnMsIGVuczEgPSBiYXJlc29pbEZyYWNfbG5kX21lYW5fZW5zX2Fub21fd2F2ZTAwW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAwLF0sCiAgICAgICAgICAgICAgICAgZW5zMiA9IGJhcmVzb2lsRnJhY19sbmRfbWVhbl9lbnNfYW5vbV93YXZlMDFbd2l0aG91dF9vdXRsaWVyc19peF93YXZlMDEsXSwKICAgICAgICAgICAgICAgICBlbnMzID0gYmFyZXNvaWxGcmFjX2xuZF9tZWFuX2Vuc19hbm9tX3dhdmUwMVtsZXZlbDJhX2l4X3dhdmUwMSwgXSwKICAgICAgICAgICAgICAgICBjb2wxID0gbGNvbF93YXZlMCwgY29sMiA9IGxjb2xfd2F2ZTAxLCBjb2wzID0gbGNvbF93YXZlMDFfbGV2ZWwyLAogICAgICAgICAgICAgICAgIHlsYWIgPSAnJScsIG1haW4gPSAnYmFyZXNvaWxmcmFjJykKCmxpbmVzKHllYXJzLCBiYXJlc29pbEZyYWNfbG5kX21lYW5fc3Rhbl9hbm9tLCBjb2wgPSBzdGFuY29sLCBsdHkgPSAnc29saWQnLCBsd2QgPSAyKQoKCmxpbmVQbG90TXVsdGlFbnMoeWVhcnMgPSB5ZWFycywgYzNQZnRGcmFjX2xuZF9tZWFuX2Vuc19hbm9tX3dhdmUwMFt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMCxdLAogICAgICAgICAgICAgICAgIGVuczIgPSBjM1BmdEZyYWNfbG5kX21lYW5fZW5zX2Fub21fd2F2ZTAxW3dpdGhvdXRfb3V0bGllcnNfaXhfd2F2ZTAxLF0sCiAgICAgICAgICAgICAgICAgZW5zMyA9IGMzUGZ0RnJhY19sbmRfbWVhbl9lbnNfYW5vbV93YXZlMDFbbGV2ZWwyYV9peF93YXZlMDEsIF0sCiAgICAgICAgICAgICAgICAgY29sMSA9IGxjb2xfd2F2ZTAsIGNvbDIgPSBsY29sX3dhdmUwMSwgY29sMyA9IGxjb2xfd2F2ZTAxX2xldmVsMiwKICAgICAgICAgICAgICAgICB5bGFiID0gJyUnLCBtYWluID0gJ2MzUGZ0RnJhYycpCgpsaW5lcyh5ZWFycywgYzNQZnRGcmFjX2xuZF9tZWFuX3N0YW5fYW5vbSwgY29sID0gc3RhbmNvbCwgbHR5ID0gJ3NvbGlkJywgbHdkID0gMikKCgpsaW5lUGxvdE11bHRpRW5zKHllYXJzID0geWVhcnMsIGM0UGZ0RnJhY19sbmRfbWVhbl9lbnNfYW5vbV93YXZlMDBbd2l0aG91dF9vdXRsaWVyc19peF93YXZlMDAsXSwKICAgICAgICAgICAgICAgICBlbnMyID0gYzRQZnRGcmFjX2xuZF9tZWFuX2Vuc19hbm9tX3dhdmUwMVt3aXRob3V0X291dGxpZXJzX2l4X3dhdmUwMSxdLAogICAgICAgICAgICAgICAgIGVuczMgPSBjNFBmdEZyYWNfbG5kX21lYW5fZW5zX2Fub21fd2F2ZTAxW2xldmVsMmFfaXhfd2F2ZTAxLCBdLAogICAgICAgICAgICAgICAgIGNvbDEgPSBsY29sX3dhdmUwLCBjb2wyID0gbGNvbF93YXZlMDEsIGNvbDMgPSBsY29sX3dhdmUwMV9sZXZlbDIsCiAgICAgICAgICAgICAgICAgeWxhYiA9ICclJywgbWFpbiA9ICdjM1BmdEZyYWMnKQoKbGluZXMoeWVhcnMsIGM0UGZ0RnJhY19sbmRfbWVhbl9zdGFuX2Fub20sIGNvbCA9IHN0YW5jb2wsIGx0eSA9ICdzb2xpZCcsIGx3ZCA9IDIpCgpyZXNldCgpCgpsZWdlbmQoJ2JvdHRvbXJpZ2h0JywgbGVnZW5kID0gYygnd2F2ZTAwJywnd2F2ZTAxJywnd2F2ZTAxIGxldmVsMicsJ3N0YW5kYXJkJyksIGx0eSA9ICdzb2xpZCcsIGx3ZCA9IDEuNSwgY29sID0gYyhsY29sX3dhdmUwLCBsY29sX3dhdmUwMSwgbGNvbF93YXZlMDFfbGV2ZWwyLCBzdGFuY29sKSwgaW5zZXQgPSBjKDAuMDUsIDAuMTUpICkKCgojZGV2Lm9mZigpCgpgYGAgCgoKIyMgQ29uc3RyYWluaW5nIHRvIGxldmVsIDIgd2l0aCB0aGUgZW11bGF0b3IKCgoKYGBge3J9Cm51bmlmIDwtIDUwMDAwClhfdW5pZiA8LSBzYW1wX3VuaWYobnVuaWYsIG1pbnMgPSByZXAoMCwzMiksIG1heGVzID0gcmVwKDEsIDMyKSkKY29sbmFtZXMoWF91bmlmKSA8LSBjb2xuYW1lcyhYKQpgYGAKCgoKYGBge3J9CgojIENhbiB0aGlzIGdvIGluIGNvbW1vbiBkYXRhPyBXb3VsZCBiZSBuZWVkZWQgZm9yIGNoZWNraW5nIGVtdWxhdG9yIGZpdHMKIyBDcmVhdGUgZml0IGxpc3RzIGZvciB0aGUgY29tYmluZWQgZGF0YSB3YXZlMDAgbGV2ZWwgMWEgYW5kIHdhdmUwMQpZX2NvbnN0X2xldmVsMWFfd2F2ZTAxX3NjYWxlZF9saXN0IDwtIG1hdDJsaXN0KFlfY29uc3RfbGV2ZWwxYV93YXZlMDFfc2NhbGVkKQoKZml0X2xpc3RfY29uc3RfbGV2ZWwxYV93YXZlMDEgPC0gbWNsYXBwbHkoWCA9IFlfY29uc3RfbGV2ZWwxYV93YXZlMDFfc2NhbGVkX2xpc3QgLCBGVU4gPSBrbSwgZm9ybXVsYSA9IH4uLCBkZXNpZ24gPSBYX2xldmVsMWFfd2F2ZTAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1jLmNvcmVzID0gNCwgY29udHJvbCA9IGxpc3QodHJhY2UgPSBGQUxTRSkpCgoKYGBgCgoKYGBge3J9CgpZX2NvbnN0X2xldmVsMWFfd2F2ZTAxX3NjYWxlZF9wcmVkIDwtIG11bHRpUHJlZChZID0gWV9jb25zdF9sZXZlbDFhX3dhdmUwMV9zY2FsZWQsIFhwcmVkID0gWF91bmlmLCBmaXRfbGlzdCA9IGZpdF9saXN0X2NvbnN0X2xldmVsMWFfd2F2ZTAxKQoKYGBgCgoKCmBgYHtyfQoKCmxldmVsMl9peF9lbV91bmlmX3dhdmUwMF93YXZlMDEgPC0gd2hpY2goWV9jb25zdF9sZXZlbDFhX3dhdmUwMV9zY2FsZWRfcHJlZCRwcmVkX21lYW5bLCduYnBfbG5kX3N1bSddID4gMCAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZX2NvbnN0X2xldmVsMWFfd2F2ZTAxX3NjYWxlZF9wcmVkJHByZWRfbWVhblssJ25wcF9ubGltX2xuZF9zdW0nXSA+IDM1ICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZX2NvbnN0X2xldmVsMWFfd2F2ZTAxX3NjYWxlZF9wcmVkJHByZWRfbWVhblssJ25wcF9ubGltX2xuZF9zdW0nXSA8IDgwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFlfY29uc3RfbGV2ZWwxYV93YXZlMDFfc2NhbGVkX3ByZWQkcHJlZF9tZWFuWywnY1NvaWxfbG5kX3N1bSddID4gNzUwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFlfY29uc3RfbGV2ZWwxYV93YXZlMDFfc2NhbGVkX3ByZWQkcHJlZF9tZWFuWywnY1NvaWxfbG5kX3N1bSddIDwgMzAwMCAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZX2NvbnN0X2xldmVsMWFfd2F2ZTAxX3NjYWxlZF9wcmVkJHByZWRfbWVhblssJ2NWZWdfbG5kX3N1bSddID4gMzAwICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZX2NvbnN0X2xldmVsMWFfd2F2ZTAxX3NjYWxlZF9wcmVkJHByZWRfbWVhblssJ2NWZWdfbG5kX3N1bSddIDwgODAwCikKCgoobGVuZ3RoKGxldmVsMl9peF9lbV91bmlmX3dhdmUwMF93YXZlMDEpIC8gbnVuaWYpICogMTAwCgpgYGAKCmBgYHtyfQoKCgpgYGAKCgpgYGB7cn0KWF9zdGFuX25vcm0gPC0gbm9ybWFsaXplKG1hdHJpeChyZXAoMSwgMzIpLCBucm93ID0gMSksIHdydCA9IGxocykKCmNvbG5hbWVzKFhfdW5pZikgPC0gMTozMgoKYGBgCgoKYGBge3IsZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSAxMiwgd2FybmluZyA9IEZBTFNFfQoKI3BkZihmaWxlID0gJ2ZpZ3MvcGFpcnNfbGV2ZWwyX2l4X2VtX3VuaWZfd2F2ZTAwX3dhdmUwMS5wZGYnLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMikKCnBhcihvbWEgPSBjKDAsMCwwLDMpLCBiZyA9ICd3aGl0ZScpCgpwYW5lbF9oaXN0X2xvY2FsIDwtIGZ1bmN0aW9uKHgsIC4uLikKewogICAgdXNyIDwtIHBhcigidXNyIik7IG9uLmV4aXQocGFyKHVzcikpCiAgICBwYXIodXNyID0gYyh1c3JbMToyXSwgMCwgMS41KSApCiAgICBoIDwtIGhpc3QoeCwgcGxvdCA9IEZBTFNFKQogICAgYnJlYWtzIDwtIGgkYnJlYWtzOyBuQiA8LSBsZW5ndGgoYnJlYWtzKQogICAgeSA8LSBoJGNvdW50czsgeSA8LSB5L21heCh5KQogICAgcmVjdChicmVha3NbLW5CXSwgMCwgYnJlYWtzWy0xXSwgeSwgY29sID0gImN5YW4iLCAuLi4pCn0KCnBhaXJzKHJiaW5kKFhfdW5pZltsZXZlbDJfaXhfZW1fdW5pZl93YXZlMDBfd2F2ZTAxLCBdLCBYX3N0YW5fbm9ybSksCiAgICAgIGdhcCA9IDAsIGxvd2VyLnBhbmVsID0gTlVMTCwgeGxpbSA9IGMoMCwxKSwgeWxpbSA9IGMoMCwxKSwKICAgICAgcGFuZWwgPSBkZnVuY191cF90cnV0aCwKICAgICAgZGlhZy5wYW5lbCA9IHBhbmVsX2hpc3RfbG9jYWwsCiAgICAgIGNleC5sYWJlbHMgPSAxLAogICAgICBjb2wuYXhpcyA9ICd3aGl0ZScsCiAgICAgIGRmdW5jX2NvbCA9IHJiCiAgICAgICkKCgppbWFnZS5wbG90KGxlZ2VuZC5vbmx5ID0gVFJVRSwKICAgICAgICAgICB6bGltID0gYygwLDEpLAogICAgICAgICAgIGNvbCA9IHJiLAogICAgICAgICAgIGxlZ2VuZC5hcmdzID0gbGlzdCh0ZXh0ID0gJ0RlbnNpdHkgb2YgbW9kZWwgcnVucyBtYXRjaGluZyB0aGUgY3JpdGVyaWEnLCBzaWRlID0gMywgbGluZSA9IDEpLAogICAgICAgICAgIGxlZ2VuZC5zaHJpbmsgPSAwLjYsCiAgICAgICAgICAgaG9yaXpvbnRhbCA9IFRSVUUKKQoKbGVnZW5kKCdsZWZ0JywgbGVnZW5kID0gcGFzdGUoMTozMiwgY29sbmFtZXMobGhzKSksIGNleCA9IDEsIGJ0eSA9ICduJykKCiNkZXYub2ZmKCkKYGBgCgo=